#include "../../Header/Header.h"
#include "../ImageTGA.h"
#include "TextureEx.h"

TextureEx::~TextureEx()
{
	if (m_bIsLoaded)
	{
		glDeleteTextures(m_iTextures, m_TBO);
		SAFE_DEL_ARRAY(m_TBO);
	}
	printf("Texture Ex\n");
}

void TextureEx::Init2D(char** strFileTextures, int iCount)
{
	m_TextureTarget = GL_TEXTURE_2D;
	m_iTextures = iCount;
	m_strFiles = new char*[m_iTextures];
	for (int i = 0; i < m_iTextures; i++)
	{
		strcpy(m_strFiles[i], strFileTextures[i]);
	}
}

void TextureEx::Init2D(char* strFileTexture)
{
	Init2D(&strFileTexture, 1);
}

void TextureEx::InitCube(char** strFileTextures, int iCount)
{
	m_TextureTarget = GL_TEXTURE_CUBE_MAP;
	m_iTextures = iCount;
	m_strFiles = new char*[m_iTextures];
	for (int i = 0; i < m_iTextures; i++)
	{
		strcpy(m_strFiles[i], strFileTextures[i]);
	}
}

void TextureEx::LoadTexture2D()
{
	//Init list textures id
	if (!m_TBO)
		SAFE_DEL_ARRAY(m_TBO);
	m_TBO = new GLuint[m_iTextures];

	//Generate Texture Buffer
	glGenTextures(m_iTextures, m_TBO);

	//Binding texture data
	for (int i = 0; i < m_iTextures; i++)
	{
		//Texture info
		int iWidth, iHeight, iBPP;
		char* imageData = NULL;
		GLenum eTextureFormat;

		//Load texture data from TGA file
		imageData = LoadTGA(m_strFiles[i], &iWidth, &iHeight, &iBPP);
		switch (iBPP)
		{
		case 24:
			eTextureFormat = GL_RGB;
			break;
		case 32:
			eTextureFormat = GL_RGBA;
			break;
		default:
			SAFE_DEL_ARRAY(m_TBO);
			SAFE_DEL_ARRAY(imageData);
			return;
		}

		glActiveTexture(GL_TEXTURE0 + i);
		glBindTexture(GL_TEXTURE_2D, m_TBO[i]);
		glTexImage2D(GL_TEXTURE_2D, 0, eTextureFormat, iWidth, iHeight, 0, eTextureFormat, GL_UNSIGNED_BYTE, imageData);

		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
		glGenerateMipmap(GL_TEXTURE_2D);

		glActiveTexture(GL_TEXTURE0 + i);
		glBindTexture(GL_TEXTURE_2D, 0);
		SAFE_DEL_ARRAY(imageData);
	}
}

void TextureEx::LoadTextureCube()
{
	//Texture Info
	ImageTGA* ImgSrcData = new ImageTGA[m_iTextures];

	glGenTextures(1, m_TBO);
	glBindTexture(GL_TEXTURE_CUBE_MAP, m_TBO[0]);
	for (int i = 0; i<6; i++)
	{
		ImgSrcData[i].cData = LoadTGA(m_strFiles[i], &ImgSrcData[i].iWidth, &ImgSrcData[i].iHeight, &ImgSrcData[i].iBpp);
		glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, ImgSrcData[i].iWidth, ImgSrcData[i].iHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, ImgSrcData[i].cData);
	}

	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glBindTexture(GL_TEXTURE_CUBE_MAP, 0);

	SAFE_DEL_ARRAY(ImgSrcData);
}

void TextureEx::Load()
{
	if (!m_bIsLoaded)
	{
		switch (m_TextureTarget)
		{
		case GL_TEXTURE_2D:
			LoadTexture2D();
			break;
		case GL_TEXTURE_CUBE_MAP:
			LoadTextureCube();
			break;
		default:
			break;
		}
		m_bIsLoaded = true;
		SAFE_DEL_ARRAY(m_strFiles);
	}
}

void TextureEx::Render(const Shader* sha)
{
	switch (m_TextureTarget)
	{
	case GL_TEXTURE_2D:
	{
						  for (int i = 0; i < m_iTextures; i++)
						  {
							  if (sha->u_Sampler[i] != -1)
							  {
								  glActiveTexture(GL_TEXTURE0 + i);
								  glBindTexture(GL_TEXTURE_2D, m_TBO[i]);
								  glUniform1i(sha->u_Sampler[i], i);
							  }
						  }
	}
		break;
	case GL_TEXTURE_CUBE_MAP:
	{
							if (sha->u_SamplerCube != -1)
							{
								glActiveTexture(GL_TEXTURE0);
								glBindTexture(GL_TEXTURE_CUBE_MAP, m_TBO[0]);
								glUniform1i(sha->u_SamplerCube, 0);
							}
	}
		break;
	default:
		break;
	}
}

void TextureEx::Unrender()
{
	switch (m_TextureTarget)
	{
	case GL_TEXTURE_2D:
	{
						  for (int i = 0; i < m_iTextures; i++)
						  {
								  glActiveTexture(GL_TEXTURE0 + i);
								  glBindTexture(GL_TEXTURE_2D, 0);
						  }
	}
		break;
	case GL_TEXTURE_CUBE_MAP:
	{
							glActiveTexture(GL_TEXTURE0);
							glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
	}
		break;
	default:
		break;
	}
}

TextureEx* TextureEx::Reference()
{
	if (!m_bIsLoaded)
		this->Load();
	m_iUser++;
	return this;
}

void TextureEx::Dereference()
{
	if (m_iUser > 0)
		m_iUser--;
	else
	{
		glDeleteBuffers(1, m_TBO);
		SAFE_DEL_ARRAY(m_TBO);
		m_bIsLoaded = false;
	}
}